package com.wanghlme.bookstore.util.common.impl;

import com.wanghlme.bookstore.bean.VerifyCode;
import com.wanghlme.bookstore.util.common.IVerifyCodeGenerator;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

@Slf4j
public class VerifyCodeImpl implements IVerifyCodeGenerator {

    private static final String[] VERIFY_CODE_FONT_TYPES = {"\u5b8b\u4f53", "\u65b0\u5b8b\u4f53", "\u9ed1\u4f53", "\u6977\u4f53", "\u96b6\u4e66"};
    private static final int VERIFY_CODE_LENGTH = 4;
    private static final byte[] VERIFY_CODE_SEQUENCE = {
            'A', 'B', 'C', 'D'
            , 'E', 'F', 'G', 'H'
            , 'I', 'J', 'K', 'L'
            , 'M', 'N', 'O', 'P'
            , 'Q', 'R', 'S', 'T'
            , 'U', 'V', 'W', 'X'
            , 'Y', 'Z', 'a', 'b'
            , 'c', 'd', 'e', 'f'
            , 'g', 'h', 'i', 'j'
            , 'k', 'l', 'm', 'n'
            , 'o', 'p', 'q', 'r'
            , 's', 't', 'u', 'v'
            , 'w', 'x', 'y', 'z'
            , '2', '3', '4', '5'
            , '6', '7', '8', '9'};

    /**
     * 生成并返回验证码，将图片写入输出流
     *
     * @param width  验证码宽度
     * @param height 验证码高度
     * @param out    输出流
     * @return 验证码值
     */
    @Override
    public String getVerifyCode(int width, int height, OutputStream out) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphics = image.getGraphics();
        String randomStr = initVerifyCode(graphics, VERIFY_CODE_LENGTH, width, height);
        graphics.dispose();
        try {
            ImageIO.write(image, "JPEG", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return randomStr;
    }

    /**
     * 生成验证码对象
     *
     * @param width  验证码宽度
     * @param height 验证码高度
     * @return 验证码对象
     */
    @Override
    public VerifyCode getVerifyCode(int width, int height) {
        VerifyCode verifyCode;
        try (ByteArrayOutputStream baOut = new ByteArrayOutputStream()) {
            String code = getVerifyCode(width, height, baOut);
            verifyCode = new VerifyCode();
            verifyCode.setCode(code);
            verifyCode.setImgBytes(baOut.toByteArray());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            verifyCode = null;
        }
        return verifyCode;
    }

    /**
     * 初始化验证码字符串及初始图形
     *
     * @param graphics   图形
     * @param codeLength 验证码长度
     * @param width      图形宽度
     * @param height     图形高度
     * @return 验证码字符串
     */
    private static String initVerifyCode(Graphics graphics, int codeLength, int width, int height) {
        byte[] codePrepare = VERIFY_CODE_SEQUENCE;

        if (codeLength == 0) {
            codeLength = VERIFY_CODE_LENGTH;
        }
        int codeX = width / (codeLength + 2);
        int codeY = height - 4;

        StringBuffer randomCode = new StringBuffer();

        /* 填充背景 */
        graphics.setColor(Color.WHITE);
        /* 设置矩形坐标 x y 为 0 */
        graphics.fillRect(0, 0, width, height);

        for (int k = 0; k < codeLength; k++) {
            Random random = new Random();

            /* 加入干扰线条 */
            graphics.setColor(Color.BLUE);
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int i = random.nextInt(20);
            int j = random.nextInt(20);
            graphics.drawLine(x, y, x + i, y + j);

            /* 生成随机字符 */
            String tmp = String.valueOf(codePrepare[random.nextInt(codePrepare.length)]);
            randomCode.append(tmp);

            /* 用随机产生的颜色将验证码绘制到图像中，此处使用红色 */
            graphics.setColor(Color.RED);
            graphics.drawString(tmp, (k + 1) * codeX, codeY);
        }
        return randomCode.toString();
    }
}
